/*
 * Alvin Baldemeca
 * TCSS 305 - Spring 2012
 * Assignment 4 Power Paint
 */

package view.container;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JPanel;

/**
 * This class is a canvas for the Power Paint program to draw or paint on.
 * Parts of the codes were modified from the PersistnetDrawingPanel Project, from
 * the class moodle website "Spring 305A" University of Washington Tacoma.
 * @author Alvin Baldemeca
 * @version 5/10/2012
 *
 */
@SuppressWarnings("serial")
public class TetrisPaintPanel extends JPanel
{
  /**
   * The width of the frame when it is initialized.
   */
  private static final int WIDTH = 450;
  
  /**
   * The height of the frame when it is initialized.
   */
  private static final int HEIGHT = 600;
  
  /**
   * Represents boolean the value if the line tool is selected.
   */
  private boolean my_line_selected;
  
  /**
   * The point where the mouse will be clicked.
   */
  private Point my_point1;
  
  /**
   * The list of shapes to be painted, which contains the type of color, 
   * shape, and thickness information.
   */
  private final List<ShapesPP> my_shape_collection;
  
 /**
  * If the rectangle tool is selected. 
  */
  private boolean my_rect_selected;
  
  /**
   * If the ellipse tool is selected.
   */
  private boolean my_ellipse_selected;
  
  /**
   * If the pencil tool is selected.
   */
  private boolean  my_pencil_selected;
  
  /**
   * States if the grid lines are to be displayed on the panel.  
   */
  private boolean my_gridlines_selected;
  
  /**
   * The current shape that's being drawn on the Drawing Panel.
   */
  private Shape my_shape;
  
  /**
   * The color of the current shape being drawn.
   */
  private Color my_color;
  
  /**
   * The thickness of the current shape being drawn. 
   */
  private Float my_thickness;
  
  /**
   * The spaces between each grid line.
   */
  private int my_gridline_space; 
  
  /**
   * A collection of pencil starting point and end point which is used to
   * undo any drawings by the pencil tool.
   */
  private final List<Integer> my_pencil_collection;
  
  /**
   * A collection of items to color with the value of my_color.
   */
  private final List<JComponent> my_item_to_color;
  
  /**
   * Constructs the drawing panel.
   * @param the_layout the layout manager to create this panel;
   */
  public TetrisPaintPanel(final LayoutManager the_layout) 
  {
    super(the_layout);
    setPreferredSize(new Dimension(WIDTH, HEIGHT));
    setBackground(Color.WHITE);
    my_shape_collection = new ArrayList<ShapesPP>();
    my_pencil_collection = new ArrayList<Integer>();
    my_item_to_color = new ArrayList<JComponent>();
    initializeFields();
  }
  
  /**
   * Helps initialize the rest of the fields.
   */
  private void initializeFields()
  {
    my_line_selected = false;
    my_rect_selected = false;
    my_ellipse_selected = false;
    my_pencil_selected =  false;
    my_gridlines_selected = false;
    my_shape = new Line2D.Float();
    my_color = Color.GREEN;
    my_thickness = 1f;
  }

  /**
   * Records the starting point of the mouse click.
   * @param the_point the point where the mouse starts
   */
  public void recordStartPoint(final Point the_point) 
  {    
    my_point1 = the_point;
    if (my_pencil_selected)
    {
      my_pencil_collection.add(my_shape_collection.size());
    }
  }

  /**
   * Records the drag point of the mouse click.
   * @param the_point the point where the mouse was dragged
   */
  public void recordDragPoint(final Point the_point) 
  {
    if (my_line_selected)
    {
      my_shape =  new Line2D.Double(my_point1, the_point);
    }
    else if (my_rect_selected)
    {
      my_shape = new Rectangle2D.Double();
      ((RectangularShape) my_shape).setFrameFromDiagonal(my_point1, the_point);
    } 
    else if (my_ellipse_selected)
    {
      my_shape = new Ellipse2D.Double();
      ((RectangularShape) my_shape).setFrameFromDiagonal(my_point1, the_point);
    } 
    else if (my_pencil_selected)
    {
      my_shape_collection.add(new ShapesPP(new Line2D.Double(my_point1, the_point),
                                           my_color, my_thickness));
      my_point1 = the_point;
    }
    repaint();
  }
  
  /**
   * Adds my_shape to the ArrayList of shapes.
   */
  public void addShape()
  {

    if (my_rect_selected || my_ellipse_selected || my_line_selected)
    {
      my_shape_collection.add(new ShapesPP(my_shape,  my_color, my_thickness));
    }
    if (my_pencil_selected)
    {
      my_pencil_collection.add(my_shape_collection.size());
    }
  }
  
  
  /**
   * Sets the color for the tools to be used to draw shapes.
   * @param the_color the color of the shapes to be drawn.
   */
  public void selectColor(final Color the_color)
  {
    my_line_selected = false;
    my_rect_selected = false;
    my_ellipse_selected = false;
    my_pencil_selected = false;
    my_color = the_color;
    if (!my_item_to_color.isEmpty())
    {
      for (JComponent j : my_item_to_color)
      {
        j.setBackground(the_color);
        j.validate();
      }
    }
  }
  
  /**
   * Sets the selection to be able to draw a line.
   */
  public void drawLines()
  {
    my_line_selected = true;
    my_rect_selected = false;
    my_ellipse_selected = false;
    my_pencil_selected = false;
  }
  
  /**
   * Sets the selection to be able to draw a line.
   */
  public void drawRect()
  {
    my_line_selected = false;
    my_rect_selected = true;
    my_ellipse_selected = false;
    my_pencil_selected = false;
  }
  /**
   * Sets the selection to be able to draw a line.
   */
  public void drawEllipse()
  {
    my_rect_selected = false;
    my_line_selected = false;
    my_ellipse_selected = true;
    my_pencil_selected = false;
  }
  
  /**
   * Selects the pencil tool to create a shape.
   */
  public void drawPencil()
  {
    my_rect_selected = false;
    my_line_selected = false;
    my_ellipse_selected = false;
    my_pencil_selected = true;
    
  }

  /**
   * Colors the component with the value of my_color.
   * @param the_item the item which background is to be colored
   */
  public void addItemToColor(final JComponent the_item)
  {
    my_item_to_color.add(the_item);
  }
  
  /**
   * Sets the thickness for the tools to be used to draw shapes.
   * @param the_thickness the color of the shapes to be drawn.
   */
  public void setmyThickness(final Float the_thickness)
  {
    my_thickness = the_thickness;
  }
  
  /**
   * Undo the last shape drawn.
   */
  public void undo()
  {
    if (!my_pencil_collection.isEmpty() &&
        my_shape_collection.size() == my_pencil_collection.get(my_pencil_collection.size() - 1)
        )
    {
      final int end = my_pencil_collection.get(my_pencil_collection.size() - 1);
      my_pencil_collection.remove(my_pencil_collection.size() - 1);
      final int start = my_pencil_collection.get(my_pencil_collection.size() - 1);
      my_pencil_collection.remove(my_pencil_collection.size() - 1);
      
      for (int i = start; i < end; i++)
      {
        my_shape_collection.remove(start);
      }
      
    }
    else if (!my_shape_collection.isEmpty())
    {
      my_shape_collection.remove(my_shape_collection.size() - 1);
    }
    my_shape = new Rectangle2D.Double();
    repaint();
  }
  /**
   * Clears the paint panel.
   */
  public void clearPanel()
  {
    final int size = my_shape_collection.size();
    for (int i = 0; i < size; i++) 
    {
      my_shape_collection.remove(0);
    }
    my_shape = new Rectangle2D.Double();
    repaint();
  }
  
  /**
   * Sets the grid line to be drawn on the panel.
   * @param the_grid_selected if the grid line is to be drawn.
   * @param the_space the space between the grid lines.
   */
  public void setGridLines(final boolean the_grid_selected, final int the_space)
  {
    my_gridlines_selected = the_grid_selected;
    my_gridline_space = the_space;
    repaint();
  }
  @Override
  public void paintComponent(final Graphics the_graphics) 
  {
    super.paintComponent(the_graphics);
    final Graphics2D g2 = (Graphics2D) the_graphics;

    if (my_gridlines_selected)
    {
      g2.setStroke(new BasicStroke(1));
      g2.setColor(Color.BLACK);
      for (int i = 0; i <= getSize().width; i += my_gridline_space) 
      {
        g2.drawLine(i, 0, i, getSize().height);
      }
  
      for (int i = 0; i <= getSize().height; i += my_gridline_space) 
      {
        g2.drawLine(0, i, getSize().width, i);
      }
    }
    
    for (int i = 0;  i < my_shape_collection.size(); i++) 
    {
      g2.setColor(my_shape_collection.get(i).getColor());
      g2.setStroke(new BasicStroke(my_shape_collection.get(i).getThickness()));
      g2.draw(my_shape_collection.get(i).getShape());
    }
    if (my_line_selected || my_rect_selected || my_ellipse_selected)
    {
      g2.setColor(my_color);
      g2.setStroke(new BasicStroke(my_thickness));
      g2.draw(my_shape);
    }
    
  }

}
